﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using todo.Lib.NET20Fix;
using todo.Model;

namespace todo
{
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [ComVisible(true)]
    public class Host
    {
        public event EventHandler OnDocReady;
        public event EventHandler OnSaveRequest;
        public event EventHandler OnSaveAndQuitRequest;

        private static int rowIndex;
        private static int visibleRowIndex;
        private static ISet<string> collapsedItemSet;

        public void FireOnSaveAndQuitRequest(EventArgs e)
        {
            var handler = OnSaveAndQuitRequest;
            if (handler != null) handler(this, e);
        }

        public void FireOnSaveRequest(EventArgs e)
        {
            var handler = OnSaveRequest;
            if (handler != null) handler(this, e);
        }

        public void FireOnDocReady(EventArgs e)
        {
            var handler = OnDocReady;
            if (handler != null) handler(this, e);
        }

        public void test()
        {
            MessageBox.Show("test...");

//            JavaScriptSerializer js;
        }

        public string buildList()
        {
            var html =
                    @"
<tr>
        <td>
            <input type=""checkbox""/>
            <span class=""label editable"">jfldsajlkfdsa</span>
        </td>
        <td class=""editable"" tabindex=""0"">wwwww</td>
    </tr>
            ";

            var sb = new StringBuilder();
            var todoList = App.TodoList;
            if (todoList != null && todoList.Todos != null)
            {
                rowIndex = 1;
                visibleRowIndex = 0;

                collapsedItemSet = new HashSet<string>();
                if (App.TodoListFile != null && App.TodoListFile != App.TempNewFile)
                {
                    var bts =
                            App.Settings["ListState"][App.TodoListFile]["CollapsedItems"].BytesValue;
                    if (bts != null && bts.Length > 0)
                    {
//                        var ts = Encoding.Default.GetString(bts);
//                        var arr = ts.Split(',');
//                        collapsedItemSet = new HashSet<string>(arr);
                        var reader = new BinaryReader(new MemoryStream(bts));
                        try
                        {
                            while (true)
                            {
//                                var row = reader.ReadInt16();
//                                var hashPlusLength = reader.ReadInt32();
//                                collapsedItemSet.Add(row + "-" + hashPlusLength);
                                var hashCode = reader.ReadInt32();
                                collapsedItemSet.Add("" + hashCode);
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e);
                            //ignore
                        }
                        finally
                        {
                            reader.Close();
                        }
                    }
                }

                AppFuncs.UpdateTransientInfos(todoList);
                OutputTodos(sb, todoList.Todos, 0);
            }
            html = sb.ToString();

            return html;
        }

        

        public static void OutputTodos(StringBuilder sb, IList<Todo> todos, int level)
        {
            foreach (var todo in todos)
            {
                OutputTodo(sb, todo, level);
            }
        }

        private static void OutputTodo(StringBuilder sb, Todo todo, int level)
        {
            sb.Append("<tr");
            var hasTodos = todo.Todos != null && todo.Todos.Count > 0;
            if (!string.IsNullOrEmpty(todo.Id))
            {
                sb.Append(" data-id=\"").Append(todo.Id).Append('"');
            }
//            bool hidden = 
            if (hasTodos)
            {
                var row = rowIndex;
                //var key = "" + (short) row + '-' + (todo.Title.GetHashCode() + todo.Title.Length);
                var pathTitle = AppFuncs.GetPathTitle(todo);
                var key = "" + pathTitle.GetHashCode();
                if (collapsedItemSet.Contains(key))
                {
                    sb.Append(" data-expanded=\"0\"");
                    todo.Collapsed = true;
                }
                else
                {
                    sb.Append(" data-expanded=\"1\"");
                    todo.Collapsed = false;
                }
            }
            sb.Append(" data-level=\"").Append(level).AppendLine("\"");
            var clazz = "node";
            if (todo.Active == 1)
            {
                clazz += " active-todo";
            }
            if ((todo.DisplayStyle & DisplayStyle.Italic) == DisplayStyle.Italic)
            {
                clazz += " italic";
            }
            if ((todo.DisplayStyle & DisplayStyle.Bold) == DisplayStyle.Bold)
            {
                clazz += " bold";
            }
            if ((todo.DisplayStyle & DisplayStyle.Underline) == DisplayStyle.Underline)
            {
                clazz += " underline";
            }
            if (todo.Title != null && todo.Title.IndexOf('\n') != -1)
            {
                clazz += " multiline";
            }

            //
            if (todo.Checked == 1) //optimize
            {
                clazz += " checked";
            }

            var visible = IsTodoVisible(todo);
            if (visible)
            {
                if ((++visibleRowIndex)%2 != 0)
                {
                    clazz += " alt";
                }
            }
            else
            {
                clazz += " hidden";
            }

            if (hasTodos)
            {
                clazz += " parent " + (todo.Collapsed ? "collapsed" : "expanded");
            }
            else
            {
                clazz += " leaf";
            }


//            if (clazz.Length > 0)
//            {
//                sb.Append(" class=\"" + clazz.Trim() + "\"");
//            }
            sb.Append(" class=\"").Append(clazz).Append("\"");

            //
            if (todo.Reminders != null && todo.Reminders.Count > 0)
            {
                var sReminders = Interop.Interop.SerializeReminders(todo.Reminders);
                sb.Append(" data-reminders='").Append(sReminders).Append("'");
            }

            //
            if (todo.Tags != null && todo.Tags.Count > 0)
            {
                sb.Append(" data-tags='").Append(string.Join(" ", todo.Tags.ToArray())).Append("'");
            }

            //
            if (!string.IsNullOrEmpty(todo.Color))
            {
                sb.Append(" data-color='").Append(todo.Color).Append("'");
            }
            if (todo.Priority != 0)
            {
                sb.Append(" data-priority='").Append(todo.Priority).Append("'");
            }

            if (todo.CreateTime != DateTime.MinValue)
            {
                sb.Append(" data-createTime=\"").Append(todo.CreateTime.ToString("yyyyMMddHHmm")).
                        Append('"');
            }

            if(todo.Checked == 1 && todo.CheckTime != DateTime.MinValue)
            {
                sb.Append(" data-checkTime=\"").Append(todo.CheckTime.ToString("yyyyMMddHHmm")).
                        Append('"');                
            }

            //
            sb.AppendLine(">");

            var levelIndent = 24;
            var pad = levelIndent*level + 24;
            var indentHtml = BuildIndentHtml(todo);
            sb.AppendLine("<td data-col1>")
                    .Append("<div class=\"indent-wrapper\"><div class=\"indent\">")
                    .Append(indentHtml).Append("</div></div>")
                    .Append("<div class=\"node-content cell-wrapper\" style=\"padding-left:")
                    .Append(pad).Append("px\">")
                    .Append("<div class=\"node-button")
                    .Append("\" style=\"margin-left:")
                    .Append(levelIndent*level).Append("px")
                    .Append("\"></div>")
                    .Append("<input type=\"checkbox\"");
            if (todo.Checked == 1)
            {
                sb.Append(" checked=\"checked\"");
            }
            sb.Append("/>");
            sb.Append("<span class=\"markers\"></span>");
            sb.Append("<span class=\"label editable\" tabindex=\"0\">");
            sb.Append(buildHtml(todo.Title))
                    .Append("</span>")
                    .Append("</div>")
                    .AppendLine()
                    .AppendLine("</td>")
                    .Append("<td data-progress class=\"editable\" tabindex=\"0\">");
            BuildProgessHtml(sb, todo.Progress);
            //.Append(todo.Progress)
            sb.Append("</td>")
                    .AppendLine()
                    .Append("<td data-due class=\"editable\" tabindex=\"0\">")
                    .Append(buildHtml(todo.Due))
                    .Append("</td>")
                    .AppendLine()
                    .Append("<td data-desc class=\"editable\" tabindex=\"0\">")
                    .Append(buildHtml(todo.Description))
                    .Append("</td>");

            sb.AppendLine()
                    .AppendLine("</tr>");
            if (hasTodos)
            {
                OutputTodos(sb, todo.Todos, level + 1);
            }
            //
            ++rowIndex;
        }

        private static void BuildProgessHtml(StringBuilder sb, int progress)
        {
            sb.Append("<div class=\"progressBar\">")
                    .Append("<div class=\"progressBarContents\">")
                    .Append("<div class=\"value base\">")
                    .Append(progress).Append('%')
                    .Append("</div>")
                    .Append("<div class=\"progress\" style=\"width:")
                    .Append(progress).Append("%\">")
                    .Append("<div class=\"value contrast\" style=\"width:")
                    .Append(progress == 0 ? 0.0 : 10000.0/progress).Append("%;\">")
                    .Append(progress).Append("%</div>")
                    .Append("</div>") //progress
                    .Append("</div>") //progressBarContents
                    .Append("</div>"); //progressBar
        }

        private static bool IsTodoVisible(Todo todo)
        {
            todo = todo.Parent;
            while (todo != null)
            {
                if (todo.Collapsed)
                {
                    return false;
                }
                todo = todo.Parent;
            }
            return true;
        }

        private static string BuildIndentHtml(Todo todo)
        {
            var sb = new StringBuilder();
            var parent = todo.Parent;
            if (todo.IsLastChild)
            {
                sb.Append("<img src=\"image/line-ur.gif\"/>");
            }
            else
            {
                sb.Append("<img src=\"image/line-udr.gif\"/>");
            }
            while (parent != null)
            {
                var img = parent.IsLastChild
                                  ? "<img src=\"image/line-na.gif\"/>"
                                  : "<img src=\"image/line-ud.gif\"/>";

                sb.Insert(0, img);
                parent = parent.Parent;
            }
            return sb.ToString();
        }

        private static string buildHtml(string text)
        {
            if (text == null)
            {
                text = "";
            }
            var html = text;
            if (text.IndexOf('\n') != -1)
            {
                html = text.Replace("\r", "").Replace("\n", "<br/>");
            }

            if (text.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
            {
//                var urlregex = new Regex(@"(http:\/\/([\w.]+\/?)\S*)",
//                    RegexOptions.IgnoreCase | RegexOptions.Compiled);
//                html = urlregex.Replace(text, "<a href=\"$1\" target=\"_blank\">$1</a>");
                var r = new Regex("(https?://[^ ]+[^ ,.])");
                html = r.Replace(text, "<a href=\"$1\">$1</a>");
            }
            return html;
        }

        public void NotifyChange()
        {
            //Console.WriteLine("changed @" + DateTime.Now);
            App.Dirty = true;
            ++TodoApi.Instance.DocChangeCounter;
        }

        public void NotifyActiveTodoChanged()
        {
//            Debug.Print("@@@@@@@ NotifyActiveTodoChanged" + DateTime.Now);
            TodoApi.Instance.ActiveTodo = null;
            App.CmdUIManager.InvalidateCmdUI();
        }

        public bool isDueVisible()
        {
            return App.Settings.DueVisible;
        }

        public bool isProgressVisible()
        {
            return App.Settings.ProgressVisible;
        }

        public bool isDescVisible()
        {
            return App.Settings.DescVisible;
        }

        public string getColWidths()
        {
            var todoListFile = App.TodoListFile;
            if (todoListFile == null || todoListFile == App.TempNewFile)
            {
                return "[]";
            }
            var sColWidths = App.Settings["ListState"][todoListFile]["ColWidths"].StringValue;
            if (sColWidths == null)
            {
                sColWidths = "";
            }
            return "[" + sColWidths + "]";
        }

        //
        public string setupReminder(string reminders)
        {
            var frm = new ReminderSetterForm();
            frm.Reminders = reminders;
            frm.ShowDialog();
            return frm.Reminders;
        }

        public void sleep(int millis)
        {
            Thread.Sleep(millis);
        }

        public void NotifyDocReady()
        {
            FireOnDocReady(EventArgs.Empty);
        }

        public bool isDoneItemsVisible()
        {
            return App.Settings.DoneItemsVisible;
        }

        public bool isHosted()
        {
            return true;
        }

        public void save()
        {
            FireOnSaveRequest(EventArgs.Empty);
        }

        public void saveAndQuit()
        {
            FireOnSaveAndQuitRequest(EventArgs.Empty);
        }

        public void quit()
        {
            App.MainForm.Close();
        }

        public void log(string msg)
        {
            Debug.Print("host: " + msg);
        }

        public bool isGridLineVisible()
        {
            return App.Settings.GridLineVisible;
        }

        public bool isTreeLineVisible()
        {
            return App.Settings.TreeLineVisible;
        }

        public bool isHeaderVisible()
        {
            return App.Settings.HeaderVisible;
        }

        public bool isTopDownMode()
        {
            return App.Settings.TopDownMode;
        }

        public void NotifyUIUpdate()
        {
            App.CmdUIManager.InvalidateCmdUI();
        }

        public string GetThemeName()
        {
            return App.Settings.ThemeName;
        }

        public bool ShowContextMenu(int x, int y)
        {
            return App.MainForm.ShowContextMenu(x, y);
        }

        public string GetLocalizedStrings()
        {
#if zh
            var map = new Dictionary<string, string> {
                    {"header.title", "标题"},
                    {"header.progress", "进度"},
                    {"header.due", "期限"},
                    {"header.description", "描述"},
                    {"msg.todolist.empty", "待办列表为空"},
                    {"action.add", "添加"},
                    {"menu.active", "活动"},
                    {"menu.tag", "标签"},
                    {"menu.color", "颜色"},
                    {"menu.priority", "优先级"},
                    {"menu.setReminder", "设置提醒"},
                    {"tagLabels", string.Join(",", Consts.TagLabels)},
                    {"colorLabels", "无,黄,红,绿,蓝,青,灰"},
                    {"lbl.none", "无"},

                    {"action.ok", "确定"},
                    {"action.today", "今天"},
                    {"action.clear", "清除"},
                    {"monthAbbrs", "一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一,十二"},
                    {"weekDayAbbrs", "日,一,二,三,四,五,六"}
            };
            return fastJSON.JSON.Instance.ToJSON(map);
#else
            return null;
#endif
        }
    }
}